#include "plot.h"

/**
 * @brief The Canvas class          класс для назначения цвета фона графика
 */
class Canvas: public QwtPlotCanvas
{
public:
    Canvas (const QColor backgroundColor = Qt::gray,QwtPlot *plot = NULL):
        QwtPlotCanvas(plot)
    {
        setPaintAttribute(QwtPlotCanvas::BackingStore, false);
        setBorderRadius(5);
        if(QwtPainter::isX11GraphicsSystem())
        {
#if QT_VERSION <0x050000
            setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
#endif
            if(testPaintAttribute(QwtPlotCanvas::BackingStore))
            {
                setAttribute(Qt::WA_PaintOnScreen,true);
                setAttribute(Qt::WA_NoSystemBackground,true);
            }
        }
        setupPalette(backgroundColor);
    }
private:
    void setupPalette(const QColor backgroundColor)
    {
        QPalette pal = palette();
        pal.setBrush(QPalette::Window,QBrush(backgroundColor));
        setPalette(pal);
    }
};


Plot::Plot(QWidget *parent):
    QwtPlot(parent),
    VectorPaintedPoints(0),
    //    d_paintedPoints(0),
    d_interval(MIN_INTERVAL,MAX_INTERVAL),
    d_timerId(-1)
{
    d_directPainter = new QwtPlotDirectPainter();

    setAutoReplot(false);

    d_colors = new ColorPlot();
    QColor backgroundColor = d_colors->getBackgroundColor();
    setCanvas(new Canvas(backgroundColor));
    replot();
    //    for(int i = 0 ; i < 8 ; i++)
    //    {
    //        d_colors->print(i);
    //    }
    //    d_colors->print(-1);

    QString nameXBottom = tr("Время от начала файла [секунда]");
    QString nameyLeft = tr("Состояние канала смежных устройств");
    setAxisTitle(QwtPlot::xBottom, nameXBottom);
    setAxisScale(QwtPlot::xBottom,d_interval.minValue(),d_interval.maxValue());
    setAxisTitle(QwtPlot::yLeft, nameyLeft);

    BinaryScaleDraw *scaleDraw = new BinaryScaleDraw();
    //    scaleDraw->setAlignment(QwtScaleDraw::LeftScale);
    setAxisScaleDraw(QwtPlot::yLeft,scaleDraw);

    //    QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::yLeft);



    //    setAxisScale(QwtPlot::yLeft,0.0,100.0);



    QwtLegend *legend = new QwtLegend();
    this->insertLegend(legend);


    QwtPlotGrid *grid = new QwtPlotGrid();  //создаём сетку
    grid->setPen(d_colors->getGridColor(), 0.0, Qt::DotLine);
    grid->enableX(true);
    grid->enableXMin(true);
    grid->enableY(true);
    grid->enableYMin(true);
    grid->attach(this);     //указываем с чем связать сетку


}
Plot::~Plot()
{
    delete d_directPainter;
    delete d_colors;
}

void Plot::setCanvasColor()
{
    QColor color = QColorDialog::getColor();
    d_colors->setBackgroundColor(color);
    setCanvasBackground(QBrush(color,Qt::SolidPattern));
}

void Plot::killTimer()
{
    QObject::killTimer(d_timerId);

}

void Plot::start()
{
    if(d_clock.elapsed()!=0)
    {
        d_clock.restart();
    }
    else d_clock.start();
    d_timerId = startTimer(INTERVAL_TIMER_PLOT);
    replot();
}

void Plot::replot()
{
    for(int i = 0 ; i < d_curves.size(); i++ )
    {
        CurveData *data = static_cast<CurveData *> (d_curves.at(i)->data());
        data->values().lock(i);
        QwtPlot::replot();
        VectorPaintedPoints.insert(i,data->size());
        //        VectorPaintedPoints.push_back(data->size());
        data->values().unlock(i);
    }
}

void Plot::setIntervalLength(double interval)
{
    if(interval > 0.0 && interval != d_interval.width())
    {
        d_interval.setMaxValue(d_interval.minValue()+interval);
        setAxisScale(QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue());
        replot();
    }
}

void Plot::setTheme(int theme)
{
    d_theme = theme;
    d_colors->updateColors(d_theme);
    QColor backgroundColor = d_colors->getBackgroundColor();
    setCanvas(new Canvas(backgroundColor));
    updateCurveColor();
}

void Plot::updateCurve()
{
    for(int i = 0 ; i < d_curves.size() ; i++)
    {
        CurveData *data = static_cast<CurveData *>(d_curves.at(i)->data());
        data->values().lock(i);
        if(data->values().size(i)==1)
        {
            data->values().unlock(i);
            d_clock.restart();
            return;
        }
        else{
            const int numPoints = data->size();
            if(numPoints > VectorPaintedPoints.at(i))
            {
                //            qDebug() << "зашел в условие в updateCurve";
                const bool doClip = !canvas()->testAttribute(Qt::WA_PaintOnScreen);
                if(doClip)
                {
                    const QwtScaleMap xMap = canvasMap(d_curves.at(i)->xAxis());
                    const QwtScaleMap yMap = canvasMap(d_curves.at(i)->yAxis());
                    QRectF br = qwtBoundingRect(*data,VectorPaintedPoints.at(i)-1,numPoints-1);
                    const QRect clipRect = QwtScaleMap::transform(xMap, yMap, br).toRect();
                    d_directPainter->setClipRegion(clipRect);
                }
                d_directPainter->drawSeries(d_curves.at(i), VectorPaintedPoints.at(i)-1, numPoints-1);
                VectorPaintedPoints[i] = numPoints;
            }
        }
        data->values().unlock(i);
    }
    replot();
}

void Plot::incrementInterval()
{
    QwtInterval interval = d_interval;
    double min = d_interval.minValue();
    double max = d_interval.maxValue();
    double step = (max-min)/2;
    d_interval = QwtInterval(min+step,max+step);
    //    d_interval = QwtInterval(d_interval.maxValue(),d_interval.maxValue()+d_interval.width());
    for(int i = 0 ; i < d_curves.size(); i++)
    {
        CurveData *data = static_cast<CurveData *>(d_curves.at(i)->data());
        if(data->values().getFlag() == false)
        {
            killTimer();
//            d_clock.restart();
            return;
        }
        if(data->values().size(i)==1)
        {
            d_clock.restart();
            return;
        }
        data->values().clearStaleValues((interval.maxValue()+interval.minValue())/2,i);
    }

    //    CurveData *data = static_cast<CurveData *>(d_curves.at(0)->data());
    QwtScaleDiv scaleDiv = axisScaleDiv(QwtPlot::xBottom);
    scaleDiv.setInterval(d_interval);
    for(int i = 0 ; i < QwtScaleDiv::NTickTypes; i++)
    {
        QList<double> ticks = scaleDiv.ticks(i);

        for(int j = 0 ; j <ticks.size(); j++)
        {
            ticks[j] += d_interval.width()/2;
        }
        scaleDiv.setTicks(i,ticks);

    }
    setAxisScaleDiv(QwtPlot::xBottom,scaleDiv);
    for (int i = 0; i < d_curves.size() ; i++)
    {
        VectorPaintedPoints[i] = 0;
    }
    replot();


}

void Plot::decrementInterval()
{
    qDebug() << "decrementInterval";

    d_clock.restart();
    d_interval.setMinValue(MIN_INTERVAL);
    d_interval.setMaxValue(MAX_INTERVAL);
    setAxisScale(QwtPlot::xBottom, MIN_INTERVAL, MAX_INTERVAL);

    for(int i = 0 ; i < d_curves.size(); i++)
    {
        VectorPaintedPoints[i] = 0;
    }

}

void Plot::resizeEvent(QResizeEvent *event)
{
    d_directPainter->reset();
    QwtPlot::resizeEvent(event);
}

void Plot::timerEvent(QTimerEvent *event)
{
    if(event->timerId()==d_timerId)
    {
        updateCurve();
        const double elapsed = d_clock.elapsed()/1000.0;
        qDebug()<<"Plot:: elapsed: " << elapsed;
        if(elapsed > d_interval.maxValue())
            incrementInterval();
        return;
    }
    QwtPlot::timerEvent(event);
}

void Plot::showEvent(QShowEvent *)
{
    replot();
}

bool Plot::eventFilter(QObject *object, QEvent *event)
{
    if(object == canvas() && event->type() == QEvent::PaletteChange)
    {
        for(int i = 0 ; i < d_curves.size(); i++)
        {
            d_curves.at(i)->setPen(d_colors->getCurveColor(i),3);
        }
    }
    return QwtPlot::eventFilter(object,event);
}

void Plot::clearCurves()
{
    qDebug()<<"1) clearCurves():: d_curves.size(): " << d_curves.size();
    QVector<QwtPlotCurve*>::iterator it = d_curves.end();
    while(it!=d_curves.begin())
    {
        --it;
        QwtPlotCurve *curve = *it;
        CurveData *data = static_cast<CurveData *>(curve->data());
        delete data;
        curve->detach();
        //        delete d_curves.at(d_curves.size()-1)->data();
        d_curves.removeLast();
    }
    qDebug()<<"2) clearCurves():: d_curves.size(): " << d_curves.size();
}

void Plot::addCurves(int params)
{
    clearCurves();
    for(int i=0; i<params;i++)
    {
        QwtPlotCurve *curve = new QwtPlotCurve();
        curve->setStyle(QwtPlotCurve::Lines);
        curve->setRenderHint(QwtPlotItem::RenderAntialiased,true);
        curve->setOrientation(Qt::Vertical);
        curve->setPaintAttribute(QwtPlotCurve::ClipPolygons,true);
        curve->setPen(d_colors->getCurveColor(i),3);
        curve->setBrush(QBrush(d_colors->getCurveColor(i),Qt::SolidPattern));
        curve->setStyle(QwtPlotCurve::Steps);
        curve->setBaseline(2*i);
        setAxisScale(QwtPlot::yLeft,-0.5,i*2+2,1);
        //        setAxisScale(QwtPlot::yLeft,-1.0,i*2+2,1);
        //        setAxisMaxMajor(QwtPlot::yLeft,params*2);
        //        setAxisMaxMinor(QwtPlot::yLeft,0);
        CurveData *data = new CurveData(i);
        curve->setData(data);
        curve->setTitle(data->getNameParam(i));
        //                curve->attach(this);
        d_curves.push_back(curve);
    }
    for(int i = d_curves.size() ; i >0; i--)
    {
        d_curves.at(i-1)->attach(this);
    }
}

void Plot::updateCurveColor()
{
    for(int i = 0 ; i < d_curves.size(); i++)
    {
        d_curves.at(i)->setPen(d_colors->getCurveColor(i),3);
        d_curves.at(i)->setBrush(QBrush(d_colors->getCurveColor(i),Qt::SolidPattern));
    }
}

